package fun.yegang.config;



import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webauthn4j.util.ArrayUtil;
import org.apache.commons.lang3.StringUtils;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
import org.keycloak.authorization.client.resource.AuthorizationResource;
import org.keycloak.authorization.client.resource.ProtectedResource;
import org.keycloak.authorization.client.resource.ProtectionResource;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.SystemPropertiesJsonParserFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * 资源服务器配置
 */
@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

    @Autowired
    private CustomReactiveAuthorizationManager customReactiveAuthorizationManager;

    /**
     * 系统参数配置
     */
    @Autowired
    private SysParameterConfig sysConfig;

//    @Bean
//    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
//        http.oauth2ResourceServer()
//                .jwt()
//                .jwtAuthenticationConverter(jwtAuthenticationConverter())
//                .jwtDecoder(jwtDecoder())
//                .and()
//                // 认证成功后没有权限操作
//                .accessDeniedHandler(new CustomServerAccessDeniedHandler())
//                // 还没有认证时发生认证异常，比如token过期，token不合法
//                .authenticationEntryPoint(new CustomServerAuthenticationEntryPoint())
//                // 将一个字符串token转换成一个认证对象
//                .bearerTokenConverter(new ServerBearerTokenAuthenticationConverter())
//                .and()
//                .authorizeExchange()
//                // 所有以 /auth/** 开头的请求全部放行
//                .pathMatchers("/auth/**", "/favicon.ico").permitAll()
//                // 所有的请求都交由此处进行权限判断处理
//                .anyExchange()
//                .access(customReactiveAuthorizationManager)
//                .and()
//                .exceptionHandling()
//                .accessDeniedHandler(new CustomServerAccessDeniedHandler())
//                .authenticationEntryPoint(new CustomServerAuthenticationEntryPoint())
//                .and()
//                .csrf()
//                .disable()
//                .addFilterAfter(new TokenTransferFilter(), SecurityWebFiltersOrder.AUTHENTICATION);
//
//        return http.build();
//    }

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) throws IOException {

        try {
            ResourceServerRepresentation realmRepresentation = (ResourceServerRepresentation)JsonSerialization.readValue(getClass().getResourceAsStream("/realm-import.json"), ResourceServerRepresentation.class);
            System.out.printf(realmRepresentation.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

//        org.keycloak.authorization.client.Configuration configuration = JsonSerialization.readValue(getClass().getResourceAsStream("/policy-enforcer.json"), org.keycloak.authorization.client.Configuration.class);
//        Keycloak keycloak = KeycloakBuilder.builder()
//                .serverUrl(configuration.getAuthServerUrl())
//                .realm(configuration.getRealm())
//                .clientId(configuration.getResource())
//                .username("test01")
//                .password("Test*2024")
//                .clientSecret("WyCETMBf4vY9B3jQwTmlnsArhkxdiuoz")
//                .build();

        // 获取资源服务器的信息
//        ResourceServerRepresentation resourceServerInfo = keycloak.realm("sso").clientInitialAccess()..getResource();

        // 输出资源服务器信息
//        System.out.println(resourceServerInfo);

//        AuthzClient authzClient = AuthzClient.create(getClass().getResourceAsStream("/policy-enforcer.json"));
//        AuthorizationRequest request = new AuthorizationRequest();
//        AuthorizationResponse response = authzClient.authorization("test01", "Test*2024").authorize(request);
//        String rpt = response.getToken();
        // 获取资源服务器的信息

//        ResourceServerRepresentation resourceServerInfo = authzClient.getResource();


// introspect the token
//        TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);

//        System.out.println("Token status is: " + requestingPartyToken.getActive());
//        System.out.println("Permissions granted by the server: ");
//
//        for (Permission granted : requestingPartyToken.getPermissions()) {
//            System.out.println(granted);
//        }
        http

//                .oauth2Login(withDefaults())
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt->
                                jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
                        // 认证成功后没有权限操作
                        .accessDeniedHandler(new CustomServerAccessDeniedHandler())
                        // 还没有认证时发生认证异常，比如token过期，token不合法
                        .authenticationEntryPoint(new CustomServerAuthenticationEntryPoint())
                        // 将一个字符串token转换成一个认证对象
                        .bearerTokenConverter(new ServerBearerTokenAuthenticationConverter())

                )
                .authorizeExchange(authorize -> authorize
                        //白名单直接放行
                        .pathMatchers(StringUtils.join(sysConfig.getIgnoreUrls(), ",")).permitAll()
                        // 所有的请求都交由此处进行权限判断处理
                        .anyExchange()
                        .access(customReactiveAuthorizationManager)

                ).exceptionHandling(exceptionHandlingSpec ->
                        exceptionHandlingSpec.accessDeniedHandler(new CustomServerAccessDeniedHandler())
                                .authenticationEntryPoint(new CustomServerAuthenticationEntryPoint())
                )
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                .cors(ServerHttpSecurity.CorsSpec::disable)
//                .addFilterAfter(new TokenTransferFilter(), BearerTokenAuthenticationFilter.class);

        ;

        http.addFilterAfter(new TokenTransferFilter(), SecurityWebFiltersOrder.AUTHENTICATION);
        return http.build();
    }

    /**
     * 从jwt令牌中获取认证对象
     */
    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {

        // 从jwt 中获取该令牌可以访问的权限
        JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
        // 取消权限的前缀，默认会加上SCOPE_
        authoritiesConverter.setAuthorityPrefix("");
        // 从那个字段中获取权限
        authoritiesConverter.setAuthoritiesClaimName("scope");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        // 获取 principal name
        jwtAuthenticationConverter.setPrincipalClaimName("sub");
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);

        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
    }

    /**
     * 解码jwt
     */
//    public ReactiveJwtDecoder jwtDecoder() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
//        Resource resource = new FileSystemResource("/Users/huan/code/study/idea/spring-cloud-alibaba-parent/gateway-oauth2/new-authoriza-server-public-key.pem");
//        String publicKeyStr = String.join("", Files.readAllLines(resource.getFile().toPath()));
//        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
//        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
//        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
//
//        return NimbusReactiveJwtDecoder.withPublicKey(rsaPublicKey)
//                .signatureAlgorithm(SignatureAlgorithm.RS256)
//                .build();
//    }
//    private ServletPolicyEnforcerFilter createPolicyEnforcerFilter() {
//        PolicyEnforcerConfig config;
//
//        try {
//            config = JsonSerialization.readValue(getClass().getResourceAsStream("/policy-enforcer.json"), PolicyEnforcerConfig.class);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//        return new ServletPolicyEnforcerFilter(new ConfigurationResolver() {
//            @Override
//            public PolicyEnforcerConfig resolve(HttpRequest request) {
//                return config;
//            }
//        });
//    }

}
